home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume91 / libraris / sregexp1 / part02 < prev   
Encoding:
Internet Message Format  |  1992-04-20  |  47.0 KB

  1. Path: news.larc.nasa.gov!amiga-request
  2. From: amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator)
  3. Subject: v91i136: sregexp.library 11.1 - a library for regular expressions, Part02/02
  4. Reply-To: "J. Spencer" <bhgs@utcs.utoronto.ca>
  5. Newsgroups: comp.sources.amiga
  6. Message-ID: <comp.sources.amiga.v91i136@ab20.larc.nasa.gov>
  7. References: <comp.sources.amiga.v91i135@ab20.larc.nasa.gov>
  8. Date: 29 Jul 91 22:50:35 GMT
  9. Approved: tadguy@uunet.UU.NET (Tad Guy)
  10. X-Mail-Submissions-To: amiga@uunet.uu.net
  11. X-Post-Discussions-To: comp.sys.amiga.misc
  12.  
  13. Submitted-by: "J. Spencer" <bhgs@utcs.utoronto.ca>
  14. Posting-number: Volume 91, Issue 136
  15. Archive-name: libraries/sregexp-11.1/part02
  16.  
  17. #!/bin/sh
  18. # This is a shell archive.  Remove anything before this line, then unpack
  19. # it by saving it into a file and typing "sh file".  To overwrite existing
  20. # files, type "sh file -c".  You can also feed this as standard input via
  21. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  22. # will see the following message at the end:
  23. #        "End of archive 2 (of 2)."
  24. # Contents:  spath.c sregexp.c sregexp.doc
  25. # Wrapped by tadguy@ab20 on Mon Jul 29 18:50:33 1991
  26. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  27. if test -f 'spath.c' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'spath.c'\"
  29. else
  30. echo shar: Extracting \"'spath.c'\" \(12861 characters\)
  31. sed "s/^X//" >'spath.c' <<'END_OF_FILE'
  32. X
  33. X/**********************************************************************
  34. X * This is the stuff for matching to a wildcarded path. see the docs  *
  35. X *                                      *
  36. X *                                      *
  37. X *  Copyright (c) 1991 by Jon Spencer.                                *
  38. X *                                      *
  39. X *  Revision history:                              *
  40. X *    May 10, 1991        First version basically completed          *
  41. X *                                      *
  42. X **********************************************************************/
  43. X
  44. X#include "sregexp.h"
  45. X
  46. Xextern struct DosLibrary *DOSBase;
  47. X
  48. X#ifdef __DEBUG__
  49. Xvoid puts(char *);
  50. Xvoid printf(char *, ...);
  51. X#endif
  52. X
  53. X#define ROOT    ((struct RootNode *)DOSBase->dl_Root)
  54. X#define INFO    ((struct DosInfo *)ROOT->rn_Info<<2)
  55. X#define DEVC(a) ((struct DeviceList *)a<<2)
  56. X
  57. Xstruct SpathInfo *
  58. Xanchorpath(anc,wld)
  59. Xchar *anc,*wld;
  60. X/* This is routine sets everything up for matching wildcard paths.
  61. X   It does the expansion of any wildcards in the volume node part
  62. X   of the path, if any where specified, and gets ready to roll. */
  63. X{
  64. X    struct SpathInfo *spi;
  65. X    struct SpathNode *spn;
  66. X    BPTR lock;
  67. X    register char *q;
  68. X    char *node,*p,c;
  69. X    struct DeviceList *dvc;
  70. X    struct SregExp *pat;
  71. X
  72. X
  73. X    if (!(spi = getmem(sizeof(struct SpathInfo)))) {
  74. X    report(MEM_ERROR);
  75. X    return NULL;
  76. X    }
  77. X    NewList((struct List *)spi);
  78. X
  79. X    for (q = wld; *q != ':' && *q != '/' && *q; q++) ;
  80. X
  81. X    if (*q == ':') {
  82. X    if (!(node = getmem(q - wld + 1))) {
  83. X        report(MEM_ERROR);
  84. X        freemem(spi,sizeof(struct SpathInfo));
  85. X        return NULL;
  86. X    }
  87. X    for (q = wld, p = node; *q != ':'; )
  88. X        *p++ = *q++;
  89. X    *p = 0;
  90. X
  91. X    pat = parsesregexp(node);
  92. X    freemem(node,strlen(node)+1);
  93. X    if (!pat) {
  94. X        freemem(spi,sizeof(struct SpathInfo));
  95. X        return NULL;
  96. X    }
  97. X
  98. X    /* Check if there is no path to parse */
  99. X    if (*(q+1)) {
  100. X        if (!(spi->spi_SregList = parsepath(q+1))) {
  101. X        freesregexp(pat);
  102. X        freemem(spi,sizeof(struct SpathInfo));
  103. X        return NULL;
  104. X        }
  105. X    } else
  106. X        spi->spi_SregList = NULL;
  107. X
  108. X    if (pat->sre_Type == SRP_NULL) {  /* check for paths matching ":..." */
  109. X
  110. X        if (!(lock = Lock(anc,SHARED_LOCK))) {
  111. X        freesregexp(pat);
  112. X        freespathinfo(spi);
  113. X        return NULL;
  114. X        }
  115. X        if (!(node = getmem(2))) {
  116. X        report(MEM_ERROR);
  117. X        UnLock(lock);
  118. X        freesregexp(pat);
  119. X        freespathinfo(spi);
  120. X        return NULL;
  121. X        }
  122. X        node[0] = ':';
  123. X        node[1] = 0;
  124. X        if (!(spn = makespathnode(lock,node,spi->spi_SregList))) {
  125. X        UnLock(lock);
  126. X        freemem(node,2);
  127. X        freesregexp(pat);
  128. X        freespathinfo(spi);
  129. X        return NULL;
  130. X        }
  131. X        spn->spn_NodeName = node;
  132. X        AddTail((struct List *)spi,(struct Node *)spn);
  133. X        UnLock(lock);
  134. X    } else {
  135. X        for (dvc = DEVC(INFO->di_DevInfo); dvc; dvc = DEVC(dvc->dl_Next)) {
  136. X        p = (char *)dvc->dl_Name<<2;
  137. X        if (matchnsregexp(p+1,pat,FALSE,*p)) {
  138. X            if (!(node = getmem(*p+2))) {
  139. X            report(MEM_ERROR);
  140. X            freesregexp(pat);
  141. X            freespathinfo(spi);
  142. X            return NULL;
  143. X            }
  144. X            for (c = *p++, q = node; c > 0; c--)
  145. X            *q++ = *p++;
  146. X            *q++ = ':';
  147. X            *q = 0;
  148. X            if (dvc->dl_Type == DLT_DEVICE) {
  149. X            lock = Lock(node,SHARED_LOCK);  /* ignore non-filesystem devices */
  150. X            if (!lock)
  151. X                continue;
  152. X            UnLock(lock);
  153. X            }
  154. X            if (!(spn = makespathnode(NULL,node,spi->spi_SregList))) {
  155. X            freemem(node,strlen(node)+1);
  156. X
  157. X            freespathinfo(spi);
  158. X            return NULL;
  159. X            }
  160. X            spn->spn_NodeName = node;
  161. X            AddTail((struct List *)spi,(struct Node *)spn);
  162. X        }
  163. X        }
  164. X    }
  165. X    freesregexp(pat);
  166. X    } else {
  167. X    /* check if there is any path to parse */
  168. X    if (*wld) {
  169. X        if (!(spi->spi_SregList = parsepath(wld))) {
  170. X        freemem(spi,sizeof(struct SpathInfo));
  171. X        return NULL;
  172. X        }
  173. X    } else
  174. X        spi->spi_SregList = NULL;
  175. X
  176. X    if (!(spn = makespathnode(NULL,anc,spi->spi_SregList)))
  177. X        freespathinfo(spi);
  178. X    AddTail((struct List *)spi,(struct Node *)spn);
  179. X    }
  180. X    return spi;
  181. X}
  182. X
  183. X#undef ROOT
  184. X#undef INFO
  185. X#undef DEVC
  186. X
  187. Xstruct SregList *
  188. Xparsepath(wld)
  189. Xchar *wld;
  190. X/* This routine takes a wildcarded path and turns it into a singly
  191. X   linked list of SregExp structures, one node for each path element. */
  192. X{
  193. X    char *q,*p,*cp,c = 1,recurse;
  194. X    struct SregExp *sre;
  195. X    struct SregList *srl,*srr = NULL,*srn;
  196. X
  197. X    if (!(cp = getmem(strlen(wld)+1))) {
  198. X    report(MEM_ERROR);
  199. X    return NULL;
  200. X    }
  201. X    strcpy(cp,wld);
  202. X
  203. X    q = cp;
  204. X    while (*q && c) {
  205. X    if (strncmp(q,".../",4) == 0) {
  206. X        recurse = SRF_RECURSE;
  207. X        q += 4;
  208. X    } else
  209. X        recurse = 0;
  210. X    p = q;
  211. X    while (*q && *q != '/') q++;
  212. X    c = *q;
  213. X    *q = 0;
  214. X    if (!(sre = parsesregexp(p)))
  215. X        goto bad;
  216. X    sre->sre_Flag |= recurse;
  217. X    *q++ = c;
  218. X    if (!srr) {
  219. X        if (!(srl = srr = getmem(sizeof(struct SregList)))) {
  220. X        report(MEM_ERROR);
  221. X        goto bad;
  222. X        }
  223. X    } else {
  224. X        if (!(srl = (srl->srl_next = getmem(sizeof(struct SregList))))) {
  225. X        report(MEM_ERROR);
  226. X        goto bad;
  227. X        }
  228. X    }
  229. X    srl->srl_next = NULL;
  230. X    srl->srl_sreg = sre;
  231. X    }
  232. X    if (c == '/')           /* If path ends in a / then just take dirs */
  233. X    srl->srl_sreg->sre_Flag |= SRF_JUSTDIRS;
  234. X
  235. X    freemem(cp,strlen(cp)+1);
  236. X    return srr;
  237. X
  238. Xbad:
  239. X    if (sre)
  240. X    freesregexp(sre);
  241. X    freemem(cp,strlen(cp)+1);
  242. X
  243. X    srl = srr;
  244. X    while (srl) {
  245. X    if (srl->srl_sreg)
  246. X        freesregexp(srl->srl_sreg);
  247. X    srn = srl->srl_next;
  248. X    freemem(srl,sizeof(struct SregList));
  249. X    srl = srn;
  250. X    }
  251. X    return NULL;
  252. X}
  253. X
  254. Xstruct SpathNode *
  255. Xmakespathnode(lock,file,sreg)
  256. XBPTR lock;
  257. Xchar *file;
  258. Xstruct SregList *sreg;
  259. X/* This routine makes a new node to be linked into the list of current
  260. X   directory locks, basically */
  261. X{
  262. X    struct SpathNode *spn;
  263. X    BPTR cdir;
  264. X
  265. X
  266. X    if (!(spn = getmem(sizeof(struct SpathNode)))) {
  267. X    report(MEM_ERROR);
  268. X    return NULL;
  269. X    }
  270. X    if (lock)
  271. X    cdir = CurrentDir(lock);
  272. X    if (!(spn->spn_Lock = Lock(file,SHARED_LOCK))) {
  273. X    freemem(spn,sizeof(struct SpathNode));
  274. X    return NULL;
  275. X    }
  276. X    spn->spn_SregList = sreg;
  277. X    if (!(Examine(spn->spn_Lock,&spn->spn_FIB))) {
  278. X    UnLock(spn->spn_Lock);
  279. X    freemem(spn,sizeof(struct SpathNode));
  280. X    return NULL;
  281. X    }
  282. X    spn->spn_Flags = 0;
  283. X    spn->spn_NodeName = NULL;
  284. X    if (lock)
  285. X    CurrentDir(cdir);
  286. X
  287. X    return spn;
  288. X}
  289. X
  290. X
  291. X
  292. X#define FILENAME    (spn->spn_FIB.fib_FileName)
  293. X#define NEXTPATH    (spn->spn_SregList->srl_next)
  294. X#define THISPATH    (spn->spn_SregList)
  295. X#define LOCK        (spn->spn_Lock)
  296. X#define FIB        (spn->spn_FIB)
  297. X#define SREG        (spn->spn_SregList->srl_sreg)
  298. X#define ISDIR        (FIB.fib_DirEntryType > 0)
  299. X#define ISRECURSE    (SREG->sre_Flag & SRF_RECURSE)
  300. X#define ISDONEONCE    (spn->spn_Flags & SPF_DONEONCE)
  301. X#define ISJUSTDIRS    (SREG->sre_Flag & SRF_JUSTDIRS)
  302. X#define WANTIT        (ISDIR ? dirs >= 0 : !ISJUSTDIRS && dirs <= 0)
  303. X#define SIGBREAKF_ANY    (SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F)
  304. X
  305. Xint
  306. Xnextfile(spi,buf,len,dirs)
  307. Xstruct SpathInfo *spi;
  308. Xchar *buf;
  309. Xint len,dirs;
  310. X/* This routine is a mess.  It jumps all over the place and is generally
  311. X   hard to follow.  The basic idea behind it is to implement recursion,
  312. X   but without using the stack.  Basically the linked list of SpathNode
  313. X   structures, anchored in the SpathInfo structure works as our stack
  314. X   for us.  "Why not just use the stack?" you ask.  Well, unfortunately,
  315. X   we have to return in the middle of the scan, each time a new match
  316. X   is found.  This would mean unrolling all of the stack that defines
  317. X   how far through the search we are to get back to the return address.
  318. X   By using the linked list of SpathInfo structures, we can preserve
  319. X   the state of the 'stack' betweem calls. */
  320. X{
  321. X    struct SpathNode *spn;
  322. X
  323. X
  324. Xtry_again:
  325. X
  326. X    if (SetSignal(0,0) & SIGBREAKF_ANY)
  327. X    return SPE_SIGBREAK;
  328. X
  329. X    spn = spi->spi_TailPred;
  330. X
  331. X    /* check if we're done. */
  332. X    if (!spn->spn_Pred) {
  333. X    report(ERROR_NO_MORE_ENTRIES);
  334. X    return SPE_ALL_DONE;
  335. X    }
  336. X
  337. X    /* check if we're at the end of the path: used to match just nodes.*/
  338. X    if (!THISPATH) {
  339. X    if (ISDONEONCE)
  340. X        goto pop;
  341. X
  342. X    spn->spn_Flags |= SPF_DONEONCE;
  343. X
  344. X    if (dirs >= 0) {
  345. X        return buildpath(spi,buf,len);
  346. X    } else
  347. X        goto pop;
  348. X    }
  349. X
  350. X    /* check if we set a delayed decend */
  351. X    if (spn->spn_Flags & SPF_DECEND)
  352. X    goto decend;
  353. X
  354. X    /* check if it matches the null string, ie parent dir */
  355. X    if (SREG->sre_Type == SRP_NULL) {
  356. X
  357. X    /* Check if its done or there is no parent. */
  358. X    if (ISDONEONCE || !ParentDir(LOCK))
  359. X        goto pop;
  360. X
  361. X    spn->spn_Flags |= SPF_DONEONCE;       /* Mark it as done. */
  362. X
  363. X    /* mark it as parent match for buildpath */
  364. X    spn->spn_Flags |= SPF_NEXTPARENT;
  365. X
  366. X    if (!(spn = makespathnode(LOCK,"/",NEXTPATH)))
  367. X        return SPE_ERROR;
  368. X    AddTail((struct List *)spi,(struct Node *)spn);
  369. X    goto try_again;
  370. X    }
  371. X
  372. X    /* Check if we can do it quickly */
  373. X    if ((SREG->sre_Type == SRP_STRING ||
  374. X                  SREG->sre_Type == SRP_ONECHAR) && !ISRECURSE) {
  375. X    BPTR cdir,lock;
  376. X
  377. X    /* Have we already done it? */
  378. X    if (ISDONEONCE)
  379. X       goto pop;
  380. X
  381. X    /* Mark it as done. */
  382. X    spn->spn_Flags |= SPF_DONEONCE;
  383. X
  384. X    cdir = CurrentDir(LOCK);
  385. X    if (SREG->sre_Type == SRP_STRING)
  386. X        lock = Lock(SREG->sre_Data.string,SHARED_LOCK);
  387. X    else {
  388. X        char n[2];
  389. X
  390. X        n[0] = SREG->sre_Data.onechar;
  391. X        n[1] = 0;
  392. X        lock = Lock(n,SHARED_LOCK);
  393. X    }
  394. X    CurrentDir(cdir);
  395. X    if (!lock)
  396. X        goto pop;
  397. X    if (!Examine(lock,&FIB)) {
  398. X        UnLock(lock);
  399. X        return SPE_ERROR;
  400. X    }
  401. X    UnLock(lock);
  402. X
  403. X    if (!NEXTPATH) {
  404. X        if (WANTIT)
  405. X        return buildpath(spi,buf,len);
  406. X        else
  407. X        goto pop;
  408. X    }
  409. X    if (ISDIR) {
  410. X        if (!(spn = makespathnode(LOCK,FILENAME,NEXTPATH))) {
  411. X        return SPE_ERROR;
  412. X        }
  413. X        AddTail((struct List *)spi,(struct Node *)spn);
  414. X        goto try_again;
  415. X    }
  416. X    goto pop;
  417. X    }
  418. X
  419. X    while (ExNext(LOCK,&FIB)) {
  420. X    if (SetSignal(0,0) & SIGBREAKF_ANY)
  421. X        return SPE_SIGBREAK;
  422. X
  423. X    if (matchsregexp(FILENAME,SREG,FALSE)) {
  424. X        if (ISDIR && ISRECURSE)
  425. X        spn->spn_Flags |= SPF_DECEND;
  426. X        if (!NEXTPATH) {
  427. X        if (WANTIT)
  428. X            return buildpath(spi,buf,len);
  429. X        } else if (ISDIR) {
  430. X        if (!(spn = makespathnode(LOCK,FILENAME,NEXTPATH))) {
  431. X            return SPE_ERROR;
  432. X        }
  433. X        AddTail((struct List *)spi,(struct Node *)spn);
  434. X        goto try_again;
  435. X        }
  436. X    }
  437. X    if (ISDIR && ISRECURSE) {
  438. Xdecend:
  439. X        spn->spn_Flags &= ~SPF_DECEND;
  440. X        if (!(spn = makespathnode(LOCK,FILENAME,THISPATH))) {
  441. X        return SPE_ERROR;
  442. X        }
  443. X        AddTail((struct List *)spi,(struct Node *)spn);
  444. X        goto try_again;
  445. X    }
  446. X    }
  447. X
  448. X    if (IoErr() != ERROR_NO_MORE_ENTRIES)
  449. X    return SPE_ERROR;
  450. X
  451. Xpop:
  452. X    RemTail((struct List*)spi);
  453. X    freespathnode(spn);
  454. X    goto try_again;
  455. X}
  456. X
  457. X#undef FILENAME
  458. X#undef NEXTPATH
  459. X#undef THISPATH
  460. X#undef LOCK
  461. X#undef FIB
  462. X#undef SREG
  463. X#undef ISDIR
  464. X#undef ISRECURSE
  465. X#undef ISDONEONCE
  466. X#undef ISJUSTDIRS
  467. X#undef WANTIT
  468. X
  469. X
  470. Xint
  471. Xbuildpath(spi,buf,len)
  472. Xstruct SpathInfo *spi;
  473. Xchar *buf;
  474. Xint len;
  475. X/* This routine turns the current 'stack' of SpathNode structures into
  476. X   a file name the AmigaDOS will like. */
  477. X{
  478. X    struct SpathNode *spn = spi->spi_Head;
  479. X    int i = 0;
  480. X    char *q;
  481. X
  482. X    if (len < 1)
  483. X    return SPE_BUFF_FULL;
  484. X
  485. X    if (spn->spn_Succ && spn->spn_NodeName) {
  486. X    while (spn->spn_Succ->spn_Succ && spn->spn_Succ->spn_NodeName) {
  487. X        spn = spn->spn_Succ;
  488. X    }
  489. X    }
  490. X
  491. X    if (q = spn->spn_NodeName) {
  492. X    while (*q && i < len)
  493. X        buf[i++] = *q++;
  494. X    if (i >= len)
  495. X        return SPE_BUFF_FULL;
  496. X    }
  497. X    while (spn->spn_Succ) {
  498. X    if (spn->spn_Flags & SPF_NEXTPARENT) {
  499. X        buf[i++] = '/';
  500. X        if (i >= len)
  501. X        return SPE_BUFF_FULL;
  502. X    } else {
  503. X        q = spn->spn_FIB.fib_FileName;
  504. X        while (*q && i < len)
  505. X        buf[i++] = *q++;
  506. X        if (i >= len)
  507. X        return SPE_BUFF_FULL;
  508. X        if (spn->spn_Succ->spn_Succ ||
  509. X              spn->spn_SregList->srl_sreg->sre_Flag & SRF_JUSTDIRS) {
  510. X        buf[i++] = '/';
  511. X        if (i >= len)
  512. X            return SPE_BUFF_FULL;
  513. X        }
  514. X    }
  515. X    spn = spn->spn_Succ;
  516. X    }
  517. X
  518. X    buf[i] = 0;
  519. X    return i;
  520. X}
  521. X
  522. Xvoid
  523. Xfreespathinfo(spi)
  524. Xstruct SpathInfo *spi;
  525. X/* This routine frees all of the resoureces tied up in a SpathInfo
  526. X   structure */
  527. X{
  528. X    struct SpathNode *spn;
  529. X    struct SregList *srl,*next;
  530. X
  531. X    while (spn = (struct SpathNode *)RemTail((struct List *)spi))
  532. X    freespathnode(spn);
  533. X
  534. X    for (srl = spi->spi_SregList; srl; srl = next) {
  535. X    freesregexp(srl->srl_sreg);
  536. X    next = srl->srl_next;
  537. X    freemem(srl,sizeof(struct SregList));
  538. X    }
  539. X
  540. X    freemem(spi,sizeof(struct SpathInfo));
  541. X}
  542. X
  543. Xvoid
  544. Xfreespathnode(spn)
  545. Xstruct SpathNode *spn;
  546. X/* This routine frees the memory and lock in a SpathNode structure. */
  547. X{
  548. X    if (spn->spn_NodeName) {
  549. X    freemem(spn->spn_NodeName,strlen(spn->spn_NodeName)+1);
  550. X    }
  551. X    UnLock(spn->spn_Lock);
  552. X    freemem(spn,sizeof(struct SpathNode));
  553. X}
  554. X
  555. X
  556. X#ifdef __DEBUG__
  557. X
  558. X/* This is some debugging stuff, not compiled into the release version. */
  559. X
  560. Xvoid
  561. Xputs(c)
  562. Xchar *c;
  563. X{
  564. X    Write(Output(),c,strlen(c));
  565. X    Write(Output(),"\n",1);
  566. X}
  567. X
  568. X#include <stdarg.h>
  569. X
  570. Xextern void vsprintf(char *, char *, va_list);
  571. X
  572. Xvoid printf(f, ...)
  573. Xchar *f;
  574. X{
  575. X    char buff[100];
  576. X    va_list va;
  577. X
  578. X    va_start(va,f);
  579. X    vsprintf(buff,f,va);
  580. X    va_end(va);
  581. X    Write(Output(),buff,strlen(buff));
  582. X}
  583. X
  584. X#ifdef    __MEMCHECK__
  585. X
  586. Xvoid *
  587. Xcheckmem(s,n,l)
  588. Xint s,l;
  589. Xchar *n;
  590. X{
  591. X    void *f;
  592. X
  593. X    f = AllocMem(s,0);
  594. X    printf("File: %10s Line %4d  Getting %5d at %x\n",n,l,s,f);
  595. X    return f;
  596. X}
  597. X
  598. Xvoid
  599. Xfreecheck(p,s,n,l)
  600. Xvoid *p;
  601. Xint s,l;
  602. Xchar *n;
  603. X{
  604. X    printf("File: %10s Line %4d  Freeing %5d at %x\n",n,l,s,p);
  605. X    FreeMem(p,s);
  606. X}
  607. X
  608. X#endif
  609. X
  610. X#endif
  611. END_OF_FILE
  612. if test 12861 -ne `wc -c <'spath.c'`; then
  613.     echo shar: \"'spath.c'\" unpacked with wrong size!
  614. fi
  615. # end of 'spath.c'
  616. fi
  617. if test -f 'sregexp.c' -a "${1}" != "-c" ; then 
  618.   echo shar: Will not clobber existing file \"'sregexp.c'\"
  619. else
  620. echo shar: Extracting \"'sregexp.c'\" \(16937 characters\)
  621. sed "s/^X//" >'sregexp.c' <<'END_OF_FILE'
  622. X
  623. X/* This is a routine to test if a string matches a regular expression.
  624. X *
  625. X *
  626. X *  The regular expression sytax is a slight extension of the regular
  627. X * AmigaDos wildcard patterns. Apparently 2.0 has added a few new things
  628. X * (well, at least a not operator) to the game.  This may or may not
  629. X * be consistant with those additions (it's the way they otta done it.)
  630. X *
  631. X * Here it is:
  632. X *
  633. X *    ?        matches any one character
  634. X *
  635. X *    #(pat)      matches zero or more occurances of the pattern pat.
  636. X *
  637. X *    (pat)       seperates out a piece of the pattern.
  638. X *
  639. X *    pat1|pat2   matches to either pat1 or pat2
  640. X *
  641. X *    '           escapes the special meaning of these symbols.
  642. X *
  643. X *    %        matches the null string.
  644. X *
  645. X *  EXTENSIONS
  646. X *
  647. X *    [chars]     will match any single character in the set chars,
  648. X *            specified as single characters or ranges seperated
  649. X *            by a -.  Ex. [af-i+] would match a, f, g, h, i, and
  650. X *            +.    If ~ is the first character in the set then the
  651. X *            set matched is the complement of the set specified.
  652. X *            Ex. [~a-z] would match any one character that is
  653. X *            not a (lower case if case sensitivity is on) letter.
  654. X *            Note that a [~a] is NOT the same as a ~[a]. The former
  655. X *            would match a 'b' but not a 'ab', whereas the latter
  656. X *            would match both.
  657. X *
  658. X *    ~(pat)      will match anything that doesn't match the pattern.
  659. X *            Note: it is illegal to repeat a not. ie #~a is illegal.
  660. X *            (So is #(~(a)) so don't even try it.) You can repeat
  661. X *            something with a not IN it, as long as it can't be
  662. X *            reduced to the form #~(pattern). (A #[~a] is OK.)
  663. X *            However ~#a has the expected effect (matches any
  664. X *            non-null string not composed entirely of a's.)
  665. X *
  666. X *    *        same as #?.
  667. X *
  668. X *
  669. X */
  670. X
  671. X#include "sregexp.h"
  672. X
  673. Xconst char wilds[] = {          /* string of the wildcards, for easy access */
  674. X            CHR_REPEAT,
  675. X            CHR_NOT,
  676. X            CHR_OPENBRACE,
  677. X            CHR_CLOSEBRACE,
  678. X            CHR_OPENSET,
  679. X            CHR_CLOSESET,
  680. X            CHR_ANYCHAR,
  681. X            CHR_NULL,
  682. X            CHR_OR,
  683. X            CHR_ESCAPE,
  684. X/*            CHR_RANGE,     <--- special case  */
  685. X            CHR_STAR,
  686. X            0
  687. X};
  688. X
  689. X#ifdef __DEBUG__
  690. Xextern void puts(char *);
  691. Xextern void printf(char *, ...);
  692. X#endif
  693. X
  694. X
  695. Xstruct SregExp *
  696. Xparsesregexp(expr)
  697. Xchar *expr;
  698. X/* This is the entry point into the parsing subroutines. */
  699. X{
  700. X    return parsesub(&expr,0);
  701. X}
  702. X
  703. Xstatic struct SregExp *
  704. Xparsesub(p,end)
  705. Xchar **p,end;
  706. X/* This routine will parse a sub expression up until the character
  707. X   'end' is encontered.  This is 0 for the whole pattern and ')'
  708. X   for a subpattern */
  709. X{
  710. X    struct SregList *list,*head=NULL,*orlist,*orhead=NULL;
  711. X    struct SregExp *sreg;
  712. X    int num = 0,ornum = 0;
  713. X
  714. X    while (**p != end) {
  715. X    if (**p == CHR_OR) {            /* deal with stuff like (ab||cd) == (ab|%|cd) */
  716. X        if (!(sreg = makenull()))
  717. X        goto cleanup;
  718. X    } else {
  719. X        if (!(sreg = parseone(p,TRUE)))  /* parse one wildcard */
  720. X        goto cleanup;
  721. X    }
  722. X    if (head) {     /* if there's already a list, just stick it on */
  723. X        if (!(list = (list->srl_next = getmem(sizeof(struct SregList))))) {
  724. X        report(MEM_ERROR);
  725. X        goto cleanup;
  726. X        }
  727. X    } else {    /* otherwise, make a new list */
  728. X        if (!(list = (head = getmem(sizeof(struct SregList))))) {
  729. X        report(MEM_ERROR);
  730. X        goto cleanup;
  731. X        }
  732. X    }
  733. X    list->srl_sreg = sreg;
  734. X    list->srl_next = NULL;
  735. X    num++;
  736. X    if (**p == CHR_OR) {        /* deal with an or */
  737. X        if (!(sreg = makesum(head,num)))
  738. X        goto cleanup;
  739. X        if (orhead) {           /* either add onto the or list */
  740. X        if (!(orlist = (orlist->srl_next = getmem(sizeof(struct SregList))))) {
  741. X            report(MEM_ERROR);
  742. X            goto cleanup;
  743. X        }
  744. X        } else {            /* or make a new or list */
  745. X        if (!(orlist = (orhead = getmem(sizeof(struct SregList))))) {
  746. X            report(MEM_ERROR);
  747. X            goto cleanup;
  748. X        }
  749. X        }
  750. X        orlist->srl_sreg = sreg;
  751. X        orlist->srl_next = NULL;
  752. X        ornum++;
  753. X        (*p)++;
  754. X        head = NULL;
  755. X        num = 0;
  756. X    }
  757. X    }
  758. X    if (head) {
  759. X    if (!(sreg = makesum(head,num)))
  760. X        goto cleanup;
  761. X    } else {
  762. X    if (!(sreg = makenull()))
  763. X        goto cleanup;
  764. X    }
  765. X    head = NULL;
  766. X    if (orhead) {       /* if this expression had an or, clean it up */
  767. X    if (!(orlist = (orlist->srl_next = getmem(sizeof(struct SregList))))) {
  768. X        report(MEM_ERROR);
  769. X        freesregexp(sreg);
  770. X        goto cleanup;
  771. X    }
  772. X    orlist->srl_sreg = sreg;
  773. X    orlist->srl_next = NULL;
  774. X    ornum++;
  775. X    if (!(sreg = makeor(orhead,ornum)))
  776. X        goto cleanup;
  777. X    }
  778. X
  779. X    return sreg;    /* sub expression successfully matched. */
  780. X
  781. Xcleanup:    /* troubles all head here to clean up */
  782. X
  783. X    list = head;
  784. X    while (list) {          /* free all the bits of the current sum */
  785. X    head = list->srl_next;
  786. X    freesregexp(list->srl_sreg);
  787. X    freemem(list,sizeof(struct SregList));
  788. X    list = head;
  789. X    }
  790. X    list = orhead;
  791. X    while (list) {          /* and all of the current or parts */
  792. X    head = list->srl_next;
  793. X    freesregexp(list->srl_sreg);
  794. X    freemem(list,sizeof(struct SregList));
  795. X    list = head;
  796. X    }
  797. X
  798. X    return NULL;        /* return the failure */
  799. X}
  800. X
  801. Xstatic struct SregExp *
  802. Xmakesum(list,num)
  803. Xstruct SregList *list;
  804. Xint num;
  805. X/* This routine takes a linked list of sreg's and joins them together
  806. X   Under the auspices of one big SRP_SUM type sreg */
  807. X{
  808. X    struct SregList *lnk;
  809. X    struct SregExp *sreg;
  810. X    int i,len=0;
  811. X    char fixed = SRF_FIXLEN;
  812. X
  813. X    if (num == 0) {
  814. X    report(ILLEGAL_ERR);
  815. X    return NULL;
  816. X    } else if (num == 1) {
  817. X    sreg = list->srl_sreg;
  818. X    freemem(list,sizeof(struct SregList));
  819. X    return sreg;
  820. X    } if (!(sreg = getmem(sizeof(struct SregExp) + num*sizeof(struct SregExp *)))) {
  821. X    report(MEM_ERROR);
  822. X    return NULL;
  823. X    }
  824. X    sreg->sre_Type = SRP_SUM;
  825. X    sreg->sre_Flag = 0;
  826. X    sreg->sre_Data.number = num;
  827. X    for (i = 0; i < num; i++) {
  828. X    len += realen(list->srl_sreg);
  829. X    fixed &= isfixed(list->srl_sreg) ? SRF_FIXLEN : 0;
  830. X    sreg->sre_List[i] = list->srl_sreg;
  831. X    lnk = list->srl_next;
  832. X    freemem(list,sizeof(struct SregList));
  833. X    list = lnk;
  834. X    }
  835. X    sreg->sre_MinLen = len;
  836. X    sreg->sre_Flag |= fixed;
  837. X    return sreg;
  838. X}
  839. X
  840. Xstatic struct SregExp *
  841. Xmakeor(list,num)
  842. Xstruct SregList *list;
  843. Xint num;
  844. X/* This does basically the same thing as makesum, except it makes
  845. X   an SRP_OR type sreg to join the list and doesn't deal with some
  846. X   special cases */
  847. X{
  848. X    struct SregList *lnk;
  849. X    struct SregExp *sreg;
  850. X    int i,len;
  851. X    char fixed = SRF_FIXLEN;
  852. X
  853. X    if (!(sreg = getmem(sizeof(struct SregExp) + num*sizeof(struct SregExp *)))) {
  854. X    report(MEM_ERROR);
  855. X    return NULL;
  856. X    }
  857. X    sreg->sre_Type = SRP_OR;
  858. X    sreg->sre_Flag = 0;
  859. X    sreg->sre_Data.number = num;
  860. X    for (i = 0; i < num; i++) {
  861. X    if (i == 0)
  862. X        len = realen(list->srl_sreg);
  863. X    else if (len != realen(list->srl_sreg)) {
  864. X        fixed = 0;
  865. X        if (len > realen(list->srl_sreg))
  866. X        len = realen(list->srl_sreg);
  867. X    }
  868. X    fixed &= isfixed(list->srl_sreg) ? SRF_FIXLEN : 0;
  869. X    sreg->sre_List[i] = list->srl_sreg;
  870. X    lnk = list->srl_next;
  871. X    freemem(list,sizeof(struct SregList));
  872. X    list = lnk;
  873. X    }
  874. X    sreg->sre_MinLen = len;
  875. X    sreg->sre_Flag |= fixed;
  876. X    return sreg;
  877. X}
  878. X
  879. Xstatic struct SregExp *
  880. Xparseone(p,cat)
  881. Xchar **p,cat;
  882. X/* This routine parses one wildcard character from the string *p,
  883. X   leaving it set up pointing to the begining of the next
  884. X   wildcard. If 'cat' is true then a string of characters will
  885. X   be grouped together as a SRP_STRING type sreg.  It may be
  886. X   false because of the scope rules of ~ and #, which only
  887. X   repeat the very next pattern. */
  888. X{
  889. X    struct SregExp *sreg;
  890. X
  891. X    switch (**p) {
  892. X    case (CHR_REPEAT) :
  893. X        (*p)++;
  894. X        if (!(sreg = parseone(p,FALSE)))
  895. X        return NULL;
  896. X        if (sreg->sre_Flag & SRF_NOT) {
  897. X        report(ILLEGAL_ERR);
  898. X        freesregexp(sreg);
  899. X        return NULL;
  900. X        }
  901. X        sreg->sre_Flag |= SRF_REPEAT;
  902. X        break;
  903. X    case (CHR_NOT) :
  904. X        (*p)++;
  905. X        if (!(sreg = parseone(p,FALSE)))
  906. X        return NULL;
  907. X        sreg->sre_Flag |= SRF_NOT;
  908. X        break;
  909. X    case (CHR_OPENBRACE) :
  910. X        (*p)++;
  911. X        sreg = parsesub(p,CHR_CLOSEBRACE);
  912. X        (*p)++;
  913. X        break;
  914. X    case (CHR_OPENSET) :
  915. X        (*p)++;
  916. X        if (!(sreg = getmem(sizeof(struct SregExp)))) {
  917. X        report(MEM_ERROR);
  918. X        return NULL;
  919. X        }
  920. X        sreg->sre_Type = SRP_SETCHAR;
  921. X        sreg->sre_Flag = SRF_FIXLEN;
  922. X        sreg->sre_MinLen = 1;
  923. X        if (!(sreg->sre_Data.setchar = makeset(p))) {
  924. X        freemem(sreg,sizeof(sreg));
  925. X        return NULL;
  926. X        }
  927. X        (*p)++;
  928. X        break;
  929. X    case (CHR_ANYCHAR) :
  930. X        (*p)++;
  931. X        if (!(sreg = getmem(sizeof(struct SregExp)))) {
  932. X        report(MEM_ERROR);
  933. X        return NULL;
  934. X        }
  935. X        sreg->sre_Type = SRP_ANYCHAR;
  936. X        sreg->sre_Flag = SRF_FIXLEN;
  937. X        sreg->sre_MinLen = 1;
  938. X        break;
  939. X    case (CHR_STAR) :
  940. X        (*p)++;
  941. X        if (!(sreg = getmem(sizeof(struct SregExp)))) {
  942. X        report(MEM_ERROR);
  943. X        return NULL;
  944. X        }
  945. X        sreg->sre_Type = SRP_ANYCHAR;
  946. X        sreg->sre_Flag = SRF_FIXLEN | SRF_REPEAT;
  947. X        sreg->sre_MinLen = 1;
  948. X        break;
  949. X    case (CHR_NULL) :
  950. X        (*p)++;
  951. X        if (!(sreg = makenull()))
  952. X        return NULL;
  953. X        break;
  954. X    case (CHR_CLOSEBRACE) :
  955. X    case (CHR_CLOSESET) :
  956. X    case (CHR_OR) :
  957. X    case (0) :
  958. X        report(ILLEGAL_ERR);
  959. X        return NULL;
  960. X    default :
  961. X        if (!(sreg = getmem(sizeof(struct SregExp)))) {
  962. X        report(MEM_ERROR);
  963. X        return NULL;
  964. X        }
  965. X        sreg->sre_Flag = SRF_FIXLEN;
  966. X        if (!cat) {
  967. X        sreg->sre_Data.onechar = onechar(p,FALSE);
  968. X        sreg->sre_Type = SRP_ONECHAR;
  969. X        sreg->sre_MinLen = 1;
  970. X        } else {
  971. X        char *q=*p;
  972. X        int len=0;
  973. X
  974. X        while (onechar(&q,FALSE))
  975. X            len++;
  976. X        sreg->sre_MinLen = len;
  977. X        if (len == 1) {
  978. X            sreg->sre_Data.onechar = onechar(p,FALSE);
  979. X            sreg->sre_Type = SRP_ONECHAR;
  980. X        } else {
  981. X            sreg->sre_Type = SRP_STRING;
  982. X            if (!(q = sreg->sre_Data.string = getmem(len+1))) {
  983. X            report(MEM_ERROR);
  984. X            freemem(sreg,sizeof(sreg));
  985. X            return NULL;
  986. X            }
  987. X            while (*q++ = onechar(p,FALSE)) ;
  988. X        }
  989. X        }
  990. X    }
  991. X    return sreg;
  992. X}
  993. X
  994. Xstatic struct SregExp *
  995. Xmakenull()
  996. X/* This routine makes an node matching the null string. */
  997. X{
  998. X    struct SregExp *sreg;
  999. X
  1000. X    if (!(sreg = getmem(sizeof(struct SregExp)))) {
  1001. X    report(MEM_ERROR);
  1002. X    return NULL;
  1003. X    }
  1004. X    sreg->sre_Type = SRP_NULL;
  1005. X    sreg->sre_Flag = SRF_FIXLEN;
  1006. X    sreg->sre_MinLen = 0;
  1007. X}
  1008. X
  1009. Xstatic char
  1010. Xonechar(p,minus)
  1011. Xchar **p,minus;
  1012. X/* this routine picks one character off the string *p.    It handles
  1013. X   escaping the special meaning of the wildcard characters, and
  1014. X   returns 0 if we're at the end of the string or the next
  1015. X   char is a wildcard.    if 'minus' is true, then the '-' is
  1016. X   treated as a wildcard, otherwise it isn't */
  1017. X{
  1018. X    if (**p == CHR_ESCAPE)
  1019. X    (*p)++;
  1020. X    else if (strchr(wilds,**p) || (minus && **p == CHR_RANGE))
  1021. X    return 0;
  1022. X    return *(*p)++;
  1023. X}
  1024. X
  1025. Xstatic char *
  1026. Xmakeset(p)
  1027. Xchar **p;
  1028. X/* this makes a table of match flags from the character specifier
  1029. X   that goes in between [ and ].  It handles a leading '~' and
  1030. X   leaves *p pointing to the closing brace. Note: This routine
  1031. X   checks to make sure the specifier ends in a ] and fails if
  1032. X   it doesn't */
  1033. X{
  1034. X    char *set,not=FALSE,ok=FALSE,s,e;
  1035. X
  1036. X    if (**p == CHR_NOT) {
  1037. X    (*p)++;
  1038. X    not = TRUE;
  1039. X    }
  1040. X    if (!(set = getmem(32))) {
  1041. X    report(MEM_ERROR);
  1042. X    return NULL;
  1043. X    }
  1044. X    for (s = 0; s < 32; s++)
  1045. X    set[s] = 0;
  1046. X    while (s = onechar(p,TRUE)) {
  1047. X    ok = TRUE;
  1048. X    if (**p == CHR_RANGE) {
  1049. X        (*p)++;
  1050. X        if (!(e = onechar(p,TRUE))) {
  1051. X        report(ILLEGAL_ERR);
  1052. X        freemem(set,32);
  1053. X        return NULL;
  1054. X        }
  1055. X        for ( ; s <= e; s++)
  1056. X        set[s/8] |= 1 << (s % 8);
  1057. X    } else
  1058. X        set[s/8] |= 1 << (s % 8);
  1059. X    }
  1060. X    if (!ok || **p != CHR_CLOSESET) {
  1061. X    report(ILLEGAL_ERR);
  1062. X    freemem(set,32);
  1063. X    return NULL;
  1064. X    }
  1065. X    if (not) {
  1066. X    for(s = 0; s < 32; s++)
  1067. X        set[s] = ~set[s];
  1068. X    }
  1069. X    return set;
  1070. X}
  1071. X
  1072. Xvoid
  1073. Xfreesregexp(sreg)
  1074. Xstruct SregExp *sreg;
  1075. X/* this routine frees up a sreg.  It correctly handles freeing the
  1076. X   subpattern elements in a SRP_SUM or SRP_OR sreg and frees the
  1077. X   match table or string from a SRP_SETCHAR or SRP_STRING sreg.
  1078. X   This is one of the externally visible routines. */
  1079. X{
  1080. X    int add = 0;
  1081. X
  1082. X    if (sreg->sre_Type == SRP_SUM || sreg->sre_Type == SRP_OR) {
  1083. X    int i;
  1084. X
  1085. X    add = sreg->sre_Data.number * sizeof(struct SregExp *);
  1086. X    for (i = 0; i < sreg->sre_Data.number; i++)
  1087. X        freesregexp(sreg->sre_List[i]);
  1088. X
  1089. X    } else if (sreg->sre_Type == SRP_STRING)
  1090. X    freemem(sreg->sre_Data.string,strlen(sreg->sre_Data.string)+1);
  1091. X    else if (sreg->sre_Type == SRP_SETCHAR)
  1092. X    freemem(sreg->sre_Data.setchar,32);
  1093. X    freemem(sreg,sizeof(struct SregExp) + add);
  1094. X}
  1095. X
  1096. Xint
  1097. Xmatchsregexp(p,sreg,up)
  1098. Xchar *p;
  1099. Xstruct SregExp *sreg;
  1100. Xint up;
  1101. X/* This is the externally visible stub to the pattern matching part
  1102. X   of sreg.  'p' is the string to match to, sreg is the preparsed
  1103. X   sreg, and up indicates if the match is case sensitive. */
  1104. X{
  1105. X    return matchnsregexp(p,sreg,up,strlen(p));
  1106. X}
  1107. X
  1108. Xint
  1109. Xmatchnsregexp(p,sreg,up,len)
  1110. Xchar *p;
  1111. Xstruct SregExp *sreg;
  1112. Xint up,len;
  1113. X/* This routine will match a sreg to a string of length 'len'. */
  1114. X/* The length, rather than NULL terminated is used to make a
  1115. X   lot of things a lot simpler */
  1116. X{
  1117. X    int res,i;
  1118. X
  1119. X    if (sreg->sre_Flag & SRF_REPEAT) {  /* deal with repeaters. */
  1120. X    char not,*h;
  1121. X
  1122. X    if (len == 0 || sreg->sre_Type == SRP_ANYCHAR) { /* always true */
  1123. X        res = TRUE;
  1124. X        goto end;
  1125. X    }
  1126. X    /* check if the lengths match up */
  1127. X    if (len < sreg->sre_MinLen || (sreg->sre_Flag & SRF_FIXLEN &&
  1128. X               (sreg->sre_MinLen == 0 || len % sreg->sre_MinLen != 0))) {
  1129. X        res = FALSE;
  1130. X        goto end;
  1131. X    }
  1132. X    not = sreg->sre_Flag & SRF_NOT;
  1133. X    sreg->sre_Flag &= ~(SRF_REPEAT | SRF_NOT);
  1134. X    if (sreg->sre_Flag & SRF_FIXLEN) { /* handle fixed lenght matches */
  1135. X        h = p;
  1136. X        while (h-p < len) {
  1137. X        if (!(res = matchnsregexp(h,sreg,up,sreg->sre_MinLen)))
  1138. X            goto end;
  1139. X        h += sreg->sre_MinLen;
  1140. X        }
  1141. X    } else {            /* and variable length ones */
  1142. X        for (i = len; i >= (sreg->sre_MinLen ? sreg->sre_MinLen : 1); i--) {
  1143. X        if (res = matchnsregexp(p,sreg,up,i)) {
  1144. X            sreg->sre_Flag |= SRF_REPEAT;
  1145. X            if (res = matchnsregexp(p+i,sreg,up,len-i))
  1146. X            break;
  1147. X            sreg->sre_Flag &= ~SRF_REPEAT;
  1148. X        }
  1149. X        }
  1150. X    }
  1151. X    sreg->sre_Flag |= SRF_REPEAT | not;
  1152. X    goto end;
  1153. X    }
  1154. X
  1155. X    /* check the lengths first for quick rejection */
  1156. X    if (len < sreg->sre_MinLen || (sreg->sre_Flag & SRF_FIXLEN && len != sreg->sre_MinLen)) {
  1157. X    res = FALSE;
  1158. X    goto end;
  1159. X    }
  1160. X
  1161. X    switch (sreg->sre_Type) {
  1162. X    case (SRP_SUM) :
  1163. X        res = matchsum(&(sreg->sre_List[0]),sreg->sre_Data.number,p,len,up);
  1164. X        break;
  1165. X    case (SRP_ONECHAR) :
  1166. X        res = len == 1 && (up ? *p == sreg->sre_Data.onechar :
  1167. X                   toupper(*p) == toupper(sreg->sre_Data.onechar));
  1168. X        break;
  1169. X    case (SRP_SETCHAR) :
  1170. X        res = len == 1 && matchset(sreg,*p) || (up ? FALSE :
  1171. X                 (isupper(*p) ? matchset(sreg,tolower(*p)) :
  1172. X                        matchset(sreg,toupper(*p))));
  1173. X        break;
  1174. X    case (SRP_ANYCHAR) :
  1175. X        res = len == 1;
  1176. X        break;
  1177. X    case (SRP_STRING) :
  1178. X        if (up)
  1179. X        res = !strncmp(p,sreg->sre_Data.string,len);
  1180. X        else
  1181. X        res = !strnicmp(p,sreg->sre_Data.string,len);
  1182. X        break;
  1183. X    case (SRP_NULL) :
  1184. X        res = len == 0;
  1185. X        break;
  1186. X    case (SRP_OR) :
  1187. X        for (i = 0; i < sreg->sre_Data.number; i++)
  1188. X        if (res = matchnsregexp(p,sreg->sre_List[i],up,len)) {
  1189. X            break;
  1190. X        }
  1191. X        break;
  1192. X    }
  1193. X
  1194. Xend:
  1195. X
  1196. X    if (sreg->sre_Flag & SRF_NOT)
  1197. X    return !res;
  1198. X    else
  1199. X    return res;
  1200. X}
  1201. X
  1202. Xstatic int
  1203. Xmatchsum(list,num,p,len,up)
  1204. Xstruct SregExp *list[];
  1205. Xint num,len,up;
  1206. Xchar *p;
  1207. X/* This routine is called by match to match the elements of a sum
  1208. X   of sregs.  It tries to be as effecient as possible, and keep
  1209. X   recursion to a minimum.  It will match any fixed length peices
  1210. X   at the begining and end first, then match any fixed length
  1211. X   peices in the middle to break the string up.  Only then does
  1212. X   it do the tiresome matches to the non-fixed length peices. */
  1213. X{
  1214. X    int i,res,o;
  1215. X
  1216. X    while (num && isfixed(list[0])) {
  1217. X    if (!(res = matchnsregexp(p,list[0],up,list[0]->sre_MinLen)))
  1218. X        return FALSE;
  1219. X    p += list[0]->sre_MinLen;
  1220. X    len -= list[0]->sre_MinLen;
  1221. X    list++;
  1222. X    num--;
  1223. X    }
  1224. X    while (num && isfixed(list[num-1])) {
  1225. X    if (!(res = matchnsregexp(p+len-list[num-1]->sre_MinLen,list[num-1],up,
  1226. X                               list[num-1]->sre_MinLen)))
  1227. X        return FALSE;
  1228. X    len -= list[num-1]->sre_MinLen;
  1229. X    num--;
  1230. X    }
  1231. X    if (num == 0)
  1232. X    return TRUE;
  1233. X
  1234. X    o = 0;
  1235. X    for (i = 1; i < num-1; i++) {
  1236. X    if (isfixed(list[i])) {
  1237. X        for ( ; len-o >= list[i]->sre_MinLen; o++) {
  1238. X        if (res = matchnsregexp(p+o,list[i],up,list[i]->sre_MinLen)) {
  1239. X            if (!(res = matchsum(list,i,p,o,up)))
  1240. X            return FALSE;
  1241. X            if (!(res = matchsum(list+(i+1),num-i-1,
  1242. X                p+o+list[i]->sre_MinLen,len-o-list[i]->sre_MinLen,up)))
  1243. X            return FALSE;
  1244. X            return TRUE;
  1245. X        }
  1246. X        }
  1247. X        return FALSE;
  1248. X    } else
  1249. X        o += realen(list[i]);
  1250. X    }
  1251. X
  1252. X    if (num == 1)
  1253. X    return matchnsregexp(p,list[0],up,len);
  1254. X
  1255. X    for (o = len; o >= list[0]->sre_MinLen; o--)
  1256. X    if (matchnsregexp(p,list[0],up,o) && matchsum(list+1,num-1,p+o,len-o,up))
  1257. X        return TRUE;
  1258. X
  1259. X    return FALSE;
  1260. X}
  1261. X
  1262. Xint
  1263. Xiswild(p)
  1264. Xchar *p;
  1265. X/* this is a very simple routine, but it is externally visible.  Returns
  1266. X   true if the string has wildcard characters (unescaped) false if
  1267. X   not */
  1268. X{
  1269. X    while (onechar(&p,FALSE)) ;
  1270. X    return *p != 0;
  1271. X}
  1272. X
  1273. Xvoid
  1274. Xreport(i)
  1275. Xint i;
  1276. X/* This routine now does set the IoErr value to more information.
  1277. X  For now it does nothing. */
  1278. X{
  1279. X    struct Process *myself;
  1280. X
  1281. X    if (myself = (struct Process *)FindTask(0))
  1282. X    myself->pr_Result2 = i;
  1283. X}
  1284. END_OF_FILE
  1285. if test 16937 -ne `wc -c <'sregexp.c'`; then
  1286.     echo shar: \"'sregexp.c'\" unpacked with wrong size!
  1287. fi
  1288. # end of 'sregexp.c'
  1289. fi
  1290. if test -f 'sregexp.doc' -a "${1}" != "-c" ; then 
  1291.   echo shar: Will not clobber existing file \"'sregexp.doc'\"
  1292. else
  1293. echo shar: Extracting \"'sregexp.doc'\" \(13775 characters\)
  1294. sed "s/^X//" >'sregexp.doc' <<'END_OF_FILE'
  1295. XTABLE OF CONTENTS
  1296. X
  1297. Xsregexp.library/AnchorPath
  1298. Xsregexp.library/BuildPath
  1299. Xsregexp.library/FreeSpathInfo
  1300. Xsregexp.library/FreeSregExp
  1301. Xsregexp.library/IsWild
  1302. Xsregexp.library/ParseSregExp
  1303. Xsregexp.library/MatchNSregExp
  1304. Xsregexp.library/MatchSregExp
  1305. Xsregexp.library/NextFile
  1306. X
  1307. Xsregexp.library/AnchorPath              sregexp.library/AnchorPath
  1308. X
  1309. X    NAME
  1310. X    AnchorPath -- get set up to match a wildcard path.
  1311. X
  1312. X    SYNOPSIS
  1313. X    spath = AnchorPath(anc, wld)
  1314. X    D0           A0    A1
  1315. X    struct SpathInfo *AnchorPath(char *, char *);
  1316. X
  1317. X    FUNCTION
  1318. X    This is the first step in matching a wildcarded path. This routine
  1319. X    will preparse all of the wildcard elements in the path and set
  1320. X    everything up for subsequent calls to NextFile.
  1321. X
  1322. X    If NULL is returned, then IoErr can be examined to find out more on
  1323. X    whatever went wrong.
  1324. X
  1325. X    The wildcarded path is made up of (almost, see bug note) any legal
  1326. X    AmigaDOS path name, with wildcard expressions in the place of file
  1327. X    and directory names.  There is one additional syntax: '.../' means
  1328. X    recursively search all sub-directories. so:
  1329. X        DH0:.../fred
  1330. X    would search all of DH0 for a (file or directory or either, see
  1331. X    NextFile) named fred.
  1332. X
  1333. X    One pretty nifty feature is that wildcards are legal in the volume
  1334. X    node part of the path.    This will match to any file system device or
  1335. X    assigned directory or volume node that the system currently has
  1336. X    mounted. So to match all of the hard drive partitions in your system
  1337. X    you would use 'DH?:.../fred'.  The root of your current device will
  1338. X    be matched only if the pattern explicitly matches a null string (ie
  1339. X    either just ':' or '%:')
  1340. X
  1341. X    INPUTS
  1342. X    anc      - a null terminated string which is the name of a
  1343. X            directory.    All paths returned by BuildPath and NextFile
  1344. X            will be relative to this directory.
  1345. X
  1346. X    wld      - the wildcarded path to be matched.
  1347. X
  1348. X    RESULTS
  1349. X    spath      - a pointer to a SpathInfo structure ready for calls to
  1350. X            NextFile.
  1351. X
  1352. X    NOTES
  1353. X    It will be most usual to pass a pointer to a null string for anc,
  1354. X    this will make all paths relative to the current working directory.
  1355. X
  1356. X    If the wildcarded path ends in a '/' then the search will match only
  1357. X    directories, and the '/' will be appended to all paths returned by
  1358. X    BuildPath and NextFile. If you specify a path ending in '/' and then
  1359. X    ask NextFile to look for only files the search will fail.  If the
  1360. X    path does not end in a '/' then no '/' will be appended to the path
  1361. X    returned, regardless of whether the match is to a file or a
  1362. X    directory.
  1363. X
  1364. X    BUGS
  1365. X    (well, possible bugs actually)  If one of the elements of the path
  1366. X    explicitly matches a null string (ie. either /%/ or just //) then
  1367. X    the routine will match to the parent directory. This works in all of
  1368. X    the cases I have tried (and the only important use, which is at the
  1369. X    beginning of the path.) I am just not terribly confident with the
  1370. X    way it's done, so if funny bugs creep up, look here first.
  1371. X
  1372. X    SEE ALSO
  1373. X    ParseSregExp, NextFile, BuildPath, FreeSpathInfo
  1374. X
  1375. Xsregexp.library/BuildPath               sregexp.library/BuildPath
  1376. X
  1377. X    NAME
  1378. X    BuildPath -- build the path to the current match to a SpathInfo
  1379. X             structure
  1380. X
  1381. X    SYNOPSIS
  1382. X    len = BuildPath(spi,buff,len)
  1383. X    D0        A0  A1     D0
  1384. X    int BuildPath(Struct SpathInfo *, char *, int);
  1385. X
  1386. X    FUNCTION
  1387. X    The path to the current match of the SpathInfo structure is copied
  1388. X    into the buffer and null terminated.  This will have unpredictable
  1389. X    results, possibly including fireworks, if it is called before the
  1390. X    first call to NextFile.
  1391. X
  1392. X    This routine will mainly be used to try again with a bigger buffer
  1393. X    if NextPath failed with SPE_BUFF_FULL.
  1394. X
  1395. X    INPUTS
  1396. X    spi      - The pointer returned by a call to AnchorPath
  1397. X
  1398. X    buff      - a buffer length len long to copy the path name into.
  1399. X
  1400. X    len      - the length of the buffer, buff.
  1401. X
  1402. X
  1403. X    RESULTS
  1404. X    len      - exactly the same as returned by NextFile.
  1405. X
  1406. X    SEE ALSO
  1407. X    NextFile, AnchorPath.
  1408. X
  1409. Xsregexp.library/FreeSpathInfo               sregexp.library/FreeSpathInfo
  1410. X
  1411. X    NAME
  1412. X    FreeSpathInfo -- free up all of the resources locked by calls
  1413. X             to AnchorPath and NextFile
  1414. X
  1415. X    SYNOPSIS
  1416. X    FreeSpathInfo(spi)
  1417. X              A0
  1418. X    void FreeSpathInfo(struct SpathInfo *);
  1419. X
  1420. X    FUNCTION
  1421. X    This will free all of the memory and file locks currently wrapped up
  1422. X    in the SpathInfo structure.  This is the ONLY way you should try to
  1423. X    free up these resources.
  1424. X
  1425. X    This routine can be called at any point, either immediately after
  1426. X    the call to AnchorPath, or after any calls to NextFile or BuildPath.
  1427. X
  1428. X    INPUTS
  1429. X    spi      - A pointer to a SpathInfo structure to be freed.
  1430. X
  1431. X    SEE ALSO
  1432. X    AnchorPath.
  1433. X
  1434. Xsregexp.library/FreeSregExp             sregexp.library/FreeSregExp
  1435. X
  1436. X    NAME
  1437. X    FreeSregExp -- free up a preparsed wildcard created by ParseSregExp
  1438. X
  1439. X    SYNOPSIS
  1440. X    FreeSregExp(sreg)
  1441. X            A0
  1442. X    void FreeSregExp(struct SregExp *);
  1443. X
  1444. X    FUNCTION
  1445. X    This routine will free all of the resources associated with a
  1446. X    preparsed wildcard expression.    This is the only legal way to free
  1447. X    the object created by ParseSregExp, and you should not try to do it
  1448. X    yourself.
  1449. X
  1450. X    INPUTS
  1451. X    sreg      - a pointer to the preparsed wildcard expression returned
  1452. X            by ParseSregExp.
  1453. X
  1454. X    SEE ALSO
  1455. X    ParseSregExp, MatchNSregExp, MatchSregExp.
  1456. X
  1457. Xsregexp.library/IsWild                      sregexp.library/IsWild
  1458. X
  1459. X    NAME
  1460. X    IsWild -- test if a string has any unescaped wildcard characters.
  1461. X
  1462. X    SYNOPSIS
  1463. X    bool = IsWild(wildcard);
  1464. X    D0          A0
  1465. X    int IsWild(char *);
  1466. X
  1467. X    FUNCTION
  1468. X    This routine merely checks if the string contains any unescaped
  1469. X    wildcard characters.  It does not actually test if the string is
  1470. X    wild.  For example, it would fail on '(this is a test)' because of
  1471. X    the round brackets, which are wildcard characters.
  1472. X
  1473. X    INPUTS
  1474. X    wildcard  - a pointer to a wildcard string.
  1475. X
  1476. X    RESULTS
  1477. X    bool      - non-zero if any unescaped wildcard characters were
  1478. X            found.
  1479. X
  1480. X    NOTES
  1481. X    This routine has very little merit, and is not really all that
  1482. X    useful.  I will probably add a routine in future versions that does
  1483. X    the same thing but takes the preparsed wildcard expression and
  1484. X    returns the unique string which it will match, or NULL.
  1485. X
  1486. X    SEE ALSO
  1487. X    ParseSregExp.
  1488. X
  1489. Xsregexp.library/ParseSregExp            sregexp.library/ParseSregExp
  1490. X
  1491. X    NAME
  1492. X    ParseSregExp -- preparse a wildcard expression for matching.
  1493. X
  1494. X    SYNOPSIS
  1495. X    sreg = ParseSregExp(wildcard)
  1496. X    D0         A0
  1497. X    struct SregExp *ParseSregExp(char *);
  1498. X
  1499. X    FUNCTION
  1500. X    A wildcard string must be preparsed before it can be passed to
  1501. X    MatchSregExp or MatchNSregExp to actually test if it matches a given
  1502. X    target string.
  1503. X
  1504. X    This function returns a pointer to the successfully created
  1505. X    structure, or NULL on failure.    On failure, IoErr() can be examined
  1506. X    to get more information on the cause of the trouble.
  1507. X    ERROR_INVALID_COMPONENT_NAME is returned if the wildcard string is
  1508. X    illegal and ERROR_NO_FREE_STORE is returned if memory allocation
  1509. X    failed.
  1510. X
  1511. X    WILDCARD SYNTAX
  1512. X    The wildcard syntax accepted is an extension of the usual AmigaDOS
  1513. X    wildcards.  Any 1.3 wildcard expression should be ok.  Apparently
  1514. X    under 2.0 they have added a not operator, and the one here may or
  1515. X    may not be compatible with the way they have done it.  (They SHOULD
  1516. X    have done it this way.)
  1517. X
  1518. X    Here is a synopsis:
  1519. X
  1520. X    ?        matches any one character
  1521. X
  1522. X    #(pat)      matches zero or more occurrences of the pattern pat.
  1523. X
  1524. X    (pat)       separates out a piece of the pattern.
  1525. X
  1526. X    pat1|pat2   matches to either pat1 or pat2
  1527. X
  1528. X    '           escapes the special meaning of these symbols.
  1529. X
  1530. X    %        matches the null string.
  1531. X
  1532. X    These are the extensions:
  1533. X
  1534. X    [chars]     will match any single character in the set chars,
  1535. X            specified as single characters or ranges separated by a
  1536. X            -.    Ex. [af-i+] would match a, f, g, h, i, and +.  If ~
  1537. X            is the first character in the set then the set matched
  1538. X            is the complement of the set specified. Ex. [~a-z] would
  1539. X            match any one character that is not a (lower case if
  1540. X            case sensitivity is on) letter. Note that a [~a] is NOT
  1541. X            the same as a ~[a]. The former would match a 'b' but not
  1542. X            a 'ab', whereas the latter would match both. Special
  1543. X            care should be taken when using this wildcard in case
  1544. X            insensitive matches. As expected, [a] would match either
  1545. X            'a' or 'A' in a case insensitive search, but [~a] would
  1546. X            match anything, since it doesn't match 'a', but would
  1547. X            match a 'A'.
  1548. X
  1549. X    ~(pat)      will match anything that doesn't match the pattern.
  1550. X            Note: it is illegal to repeat a not. ie #~a is illegal.
  1551. X            (So is #(~(a)) so don't even try it.) You can repeat
  1552. X            something with a not IN it, as long as it can't be
  1553. X            reduced to the form #~(pattern). (A #[~a] is OK.)
  1554. X            However ~#a has the expected effect (matches any
  1555. X            non-null string not composed entirely of a's.)
  1556. X
  1557. X    *        same as #?.
  1558. X
  1559. X    INPUTS
  1560. X    wildcard  - a pointer to the null terminated wildcard expression
  1561. X            string.
  1562. X
  1563. X    RETURNS
  1564. X    sreg      - a preparsed version of the wildcard expression.
  1565. X
  1566. X    SEE ALSO
  1567. X    FreeSregExp, MatchNSregExp, MatchSregExp.
  1568. X
  1569. Xsregexp.library/MatchNSregExp               sregexp.library/MatchNSregExp
  1570. X
  1571. X    NAME
  1572. X    MatchNSregExp - match a preparsed wildcard expression to a target
  1573. X
  1574. X    SYNOPSIS
  1575. X    bool = MatchNSregExp(target,sreg,case,len)
  1576. X    D0              A0     A1    D0    D1
  1577. X    int MatchNSregExp(char *, struct SregExp *, int int);
  1578. X
  1579. X    FUNCTION
  1580. X    This function tests if the given fixed length target string matches
  1581. X    the preparsed wildcard expression.
  1582. X
  1583. X    This routine is identical to MatchSregExp, except it takes a pointer
  1584. X    to a string and its length, rather than a null terminated string.
  1585. X
  1586. X    INPUTS
  1587. X    target      - the null terminated target string you wish to test
  1588. X            against the wildcard expression.
  1589. X
  1590. X    sreg      - the preparsed wildcard expression.
  1591. X
  1592. X    case      - if this is non-zero then the match is case sensitive,
  1593. X            otherwise it is case insensitive.
  1594. X
  1595. X    len      - the length of the string pointed to by target.
  1596. X
  1597. X    RESULTS
  1598. X    bool      - non-zero if the target matches the expression, zero
  1599. X            otherwise.
  1600. X
  1601. X    NOTES
  1602. X    See ParseSregExp for a discussion of the wildcard expression and the
  1603. X    tricky behaviour of character sets (ie. [...]) when the search is
  1604. X    case insensitive.
  1605. X
  1606. X    This routine is handy for matching BCPL strings.  If p is a c
  1607. X    pointer (byte, not longword address) of a BCPL string then
  1608. X
  1609. X        MatchNSregExp(p+1,sreg,case,*p)
  1610. X
  1611. X    will test the BCPL string for a match.
  1612. X
  1613. X    SEE ALSO
  1614. X    FreeSregExp, ParseSregExp, MatchSregExp.
  1615. X
  1616. Xsregexp.library/MatchSregExp            sregexp.library/MatchSregExp
  1617. X
  1618. X    NAME
  1619. X    MatchSregExp - match a preparsed wildcard expression to a target
  1620. X
  1621. X    SYNOPSIS
  1622. X    bool = MatchSregExp(target,sreg,case)
  1623. X    D0              A0     A1   D0
  1624. X    int MatchSregExp(char *, struct SregExp *, int);
  1625. X
  1626. X    FUNCTION
  1627. X    This function tests if the given null terminated target string
  1628. X    matches the preparsed wildcard expression.
  1629. X
  1630. X    This routine is identical to MatchNSregExp, except it takes a
  1631. X    pointer to a null terminated string,  rather than a string and its
  1632. X    length.
  1633. X
  1634. X    INPUTS
  1635. X    target      - the null terminated target string you wish to test
  1636. X            against the wildcard expression.
  1637. X
  1638. X    sreg      - the preparsed wildcard expression.
  1639. X
  1640. X    case      - if this is non-zero then the match is case sensitive,
  1641. X            otherwise it is case insensitive.
  1642. X
  1643. X    RESULTS
  1644. X    bool      - non-zero if the target matches the expression, zero
  1645. X            otherwise.
  1646. X
  1647. X    NOTES
  1648. X    See ParseSregExp for a discussion of the wildcard expression and the
  1649. X    tricky behaviour of character sets (ie. [...]) when the search is
  1650. X    case insensitive.
  1651. X
  1652. X    This call currently just results in the call:
  1653. X
  1654. X        MatchNSregExp(target,sreg,case,strlen(target));
  1655. X
  1656. X    but this may change in future version.
  1657. X
  1658. X    SEE ALSO
  1659. X    FreeSregExp, ParseSregExp, MatchNSregExp.
  1660. X
  1661. Xsregexp.library/NextFile                sregexp.library/NextFile
  1662. X
  1663. X    NAME
  1664. X    NextFile -- return the next (or first) file matching the path.
  1665. X
  1666. X    SYNOPSIS
  1667. X    len = NextFile(spi,buff,len,dirs)
  1668. X    D0           A0  A1    D0  D1
  1669. X    int NextFile(struct SpathInfo *, char *, int int);
  1670. X
  1671. X    FUNCTION
  1672. X    This routine copies the path to the next (or first, if this is the
  1673. X    first call) file or directory matching the wildcard in the SpathInfo
  1674. X    structure created by a call to AnchorPath.
  1675. X
  1676. X    The usual calling sequence would be:
  1677. X        AnchorPath
  1678. X        repeat while no errors and more files
  1679. X        NextFile
  1680. X        FreeSpathInfo
  1681. X
  1682. X    The length of the path is returned, or if there is an error or there
  1683. X    are no more matches a negative result is returned.  Both the
  1684. X    negative number and the Value if IoErr will give more information
  1685. X    about why the routine returned.
  1686. X
  1687. X    INPUTS
  1688. X    spi      - The pointer returned by a call to AnchorPath
  1689. X
  1690. X    buff      - a buffer length len long to copy the path name into.
  1691. X
  1692. X    len      - the length of the buffer, buff.
  1693. X
  1694. X    dirs      - if this is greater than zero, only directories will
  1695. X            match; if it is zero, both files and directories will
  1696. X            match; if it is less than zero, only files will match.
  1697. X            See the defines in the include file.
  1698. X
  1699. X    RESULTS
  1700. X    len      - on success this will be the length of the path copied
  1701. X            into the buffer. If it is less than zero, some kind of
  1702. X            special event is signalled.
  1703. X            SPE_ALL_DONE  - This signals there are no more matches
  1704. X                    to the path. IoErr will also be set to
  1705. X                    ERROR_NO_MORE_ENTRIES
  1706. X            SPE_ERROR      - Some error happened, see IoErr.
  1707. X            SPE_BUFF_FULL - The buffer you suplied was not big
  1708. X                    enough for the path name.  Get a bigger
  1709. X                    one and call BuildPath.
  1710. X            SPE_SIGBREAK  - One of the dos break signals was
  1711. X                    received by your process. This does not
  1712. X                    clear the signals, but since some
  1713. X                    searches can take a while it checks
  1714. X                    every now and again.  You can just clear
  1715. X                    the signal and call NextPath again to
  1716. X                    ignore the signal.
  1717. X
  1718. X    NOTES
  1719. X    It is meaningless to mix calls with a different value of dirs.
  1720. X    Anything passed by in a call in which you did not ask for objects of
  1721. X    a given type will not reappear in subsequent calls in which you do
  1722. X    ask for that type.
  1723. X
  1724. X    SEE ALSO
  1725. X    AnchorPath, BuildPath.
  1726. X
  1727. END_OF_FILE
  1728. if test 13775 -ne `wc -c <'sregexp.doc'`; then
  1729.     echo shar: \"'sregexp.doc'\" unpacked with wrong size!
  1730. fi
  1731. # end of 'sregexp.doc'
  1732. fi
  1733. echo shar: End of archive 2 \(of 2\).
  1734. cp /dev/null ark2isdone
  1735. MISSING=""
  1736. for I in 1 2 ; do
  1737.     if test ! -f ark${I}isdone ; then
  1738.     MISSING="${MISSING} ${I}"
  1739.     fi
  1740. done
  1741. if test "${MISSING}" = "" ; then
  1742.     echo You have unpacked both archives.
  1743.     rm -f ark[1-9]isdone
  1744. else
  1745.     echo You still need to unpack the following archives:
  1746.     echo "        " ${MISSING}
  1747. fi
  1748. ##  End of shell archive.
  1749. exit 0
  1750. -- 
  1751. Mail submissions (sources or binaries) to <amiga@uunet.uu.net>.
  1752. Mail comments to the moderator at <amiga-request@uunet.uu.net>.
  1753. Post requests for sources, and general discussion to comp.sys.amiga.misc.
  1754.